package main

import (
	"encoding/binary/be"
	"fmt"
	"rtos"

	"sdcard"
)

func checkErr(what string, err error, status sdcard.CardStatus) {
	if err != nil {
		fmt.Printf("%s: %v\n", what, err)
		for {
		}
	}
	errFlags := sdcard.OUT_OF_RANGE |
		sdcard.ADDRESS_ERROR |
		sdcard.BLOCK_LEN_ERROR |
		sdcard.ERASE_SEQ_ERROR |
		sdcard.ERASE_PARAM |
		sdcard.WP_VIOLATION |
		sdcard.LOCK_UNLOCK_FAILED |
		sdcard.COM_CRC_ERROR |
		sdcard.ILLEGAL_COMMAND |
		sdcard.CARD_ECC_FAILED |
		sdcard.CC_ERROR |
		sdcard.ERROR |
		sdcard.CSD_OVERWRITE |
		sdcard.WP_ERASE_SKIP |
		sdcard.CARD_ECC_DISABLED |
		sdcard.ERASE_RESET |
		sdcard.AKE_SEQ_ERROR
	if status &= errFlags; status != 0 {
		fmt.Printf("%s: 0x%X", what, status)
		for {
		}
	}
}

func _waitDataReady(sd sdcard.Host) {
	const wait = 500 // Timeout for SDXC: 500 ms (SDSC, SDHC: 250 ms).
	if sd.Wait(rtos.Nanosec() + wait*1e6) {
		return
	}
	fmt.Printf("data ready timeout\n")
	for {
	}
}

//emgo:const
var statusStr = [...]string{
	"?",
	"?",
	"?",
	"AKE_SEQ_ERROR",
	"?",
	"APP_CMD",
	"FX_EVENT",
	"?",
	"READY_FOR_DATA",
	"?",
	"?",
	"?",
	"?",
	"ERASE_RESET",
	"CARD_ECC_DISABLED",
	"WP_ERASE_SKIP",
	"CSD_OVERWRITE",
	"?",
	"?",
	"ERROR",
	"CC_ERROR",
	"CARD_ECC_FAILED",
	"ILLEGAL_COMMAND",
	"COM_CRC_ERROR",
	"LOCK_UNLOCK_FAILED",
	"CARD_IS_LOCKED",
	"WP_VIOLATION",
	"ERASE_PARAM",
	"ERASE_SEQ_ERROR",
	"BLOCK_LEN_ERROR",
	"ADDRESS_ERROR",
	"OUT_OF_RANGE",
}

//emgo:const
var stateStr = [...]string{
	"StateIdle",
	"StateReady",
	"StateIdent",
	"StateStby",
	"StateTran",
	"StateData",
	"StateRcv",
	"StatePrg",
	"StateDis",
	"?",
	"?",
	"?",
	"?",
	"?",
	"?",
	"StateIOOnly",
}

func printStatus(st sdcard.CardStatus) {
	fmt.Printf("Card status: ")
	fmt.Printf(stateStr[st&sdcard.CURRENT_STATE>>9])
	for n := uint(0); n < 32; n++ {
		if n == 9 {
			n = 12
			continue
		}
		if st&(1<<n) != 0 {
			fmt.Printf(",")
			fmt.Printf(statusStr[n])
		}
	}
	fmt.Printf("\n")
}

func printCID(cid sdcard.CID) {
	y, m := cid.MDT()
	pnm := cid.PNM()
	oid := cid.OID()
	prv := cid.PRV()
	fmt.Printf("Manufacturer ID:       %d\n", cid.MID())
	fmt.Printf("OEM/Application ID:    %s\n", oid[:])
	fmt.Printf("Product name:          %s\n", pnm[:])
	fmt.Printf("Product revision:      %d.%d\n", prv>>4&15, prv&15)
	fmt.Printf("Product serial number: %d\n", cid.PSN())
	fmt.Printf("Manufacturing date:    %04d-%02d\n\n", y, m)
}

func printCSD(csd sdcard.CSD) {
	csdv := csd.Version()
	fmt.Printf("CSD version:        %d\n", csdv)
	fmt.Printf("TAAC:               %d ns\n", csd.TAAC())
	fmt.Printf("NSAC:               %d clk\n", csd.NSAC())
	fmt.Printf("TRAN_SPEED:         %d kbit/s\n", csd.TRAN_SPEED())
	fmt.Printf("CCC:                0b%012b\n", csd.CCC())
	fmt.Printf("READ_BL_LEN:        %d B\n", csd.READ_BL_LEN())
	fmt.Printf("READ_BL_PARTIAL:    %t\n", csd.READ_BL_PARTIAL())
	fmt.Printf("WRITE_BLK_MISALIGN: %t\n", csd.WRITE_BLK_MISALIGN())
	fmt.Printf("READ_BLK_MISALIGN:  %t\n", csd.READ_BLK_MISALIGN())
	fmt.Printf("DSR_IMP:            %t\n", csd.DSR_IMP())
	csize := csd.C_SIZE()
	fmt.Printf("C_SIZE:             %d KiB (%d kB)\n", csize>>1, csize<<9/1000)
	fmt.Printf("ERASE_BLK_EN:       %t\n", csd.ERASE_BLK_EN())
	fmt.Printf("SECTOR_SIZE:        %d * WRITE_BL_LEN\n", csd.SECTOR_SIZE())
	fmt.Printf("WP_GRP_SIZE:        %d * SECTOR_SIZE\n", csd.WP_GRP_SIZE())
	fmt.Printf("WP_GRP_ENABLE:      %t\n", csd.WP_GRP_ENABLE())
	fmt.Printf("R2W_FACTOR:         %d\n", csd.R2W_FACTOR())
	fmt.Printf("WRITE_BL_LEN:       %d B\n", csd.WRITE_BL_LEN())
	fmt.Printf("WRITE_BL_PARTIAL:   %t\n", csd.WRITE_BL_PARTIAL())
	fmt.Printf("FILE_FORMAT:        %d\n", csd.FILE_FORMAT())
	fmt.Printf("COPY:               %t\n", csd.COPY())
	fmt.Printf("PERM_WRITE_PROTECT: %t\n", csd.PERM_WRITE_PROTECT())
	fmt.Printf("TMP_WRITE_PROTECT:  %t\n\n", csd.TMP_WRITE_PROTECT())
}

func printSCR(scr sdcard.SCR) {
	fmt.Printf("SCR_STRUCTURE:         %d\n", scr.SCR_STRUCTURE())
	fmt.Printf("SD_SPEC:               %d\n", scr.SD_SPEC())
	fmt.Printf("DATA_STAT_AFTER_ERASE: %d\n", scr.DATA_STAT_AFTER_ERASE())
	fmt.Printf("SD_SECURITY:           %d\n", scr.SD_SECURITY())
	fmt.Printf("SD_BUS_WIDTHS:         0b%04b\n", scr.SD_BUS_WIDTHS())
	fmt.Printf("SD_SPEC3:              %d\n", scr.SD_SPEC3())
	fmt.Printf("EX_SECURITY:           %d\n", scr.EX_SECURITY())
	fmt.Printf("SD_SPEC4:              %d\n", scr.SD_SPEC4())
	fmt.Printf("SD_SPECX:              %d\n", scr.SD_SPECX())
	fmt.Printf("CMD_SUPPORT:           0b%04b\n\n", scr.CMD_SUPPORT())
}

func printGroupBits(d []byte) {
	for i := 6; i > 0; i-- {
		fmt.Printf("   group %d: 0b%016b\n", i, be.Decode16(d[(6-i)*2:]))
	}
}

func printCMD6Status(d []byte) (sel sdcard.SwitchFunc) {
	fmt.Printf("CMD6 (SWITCH_FUNC) status:\n")
	fmt.Printf("- max. current: %d mA\n", be.Decode16(d[0:2]))
	fmt.Printf("- supported functions:\n")
	printGroupBits(d[2:14])
	sel = sdcard.SwitchFunc(be.Decode32(d[13:17]) & 0xFFFFFF)
	fmt.Printf("- selected functions: 0x%06x\n", sel)
	if d[17] != 0 {
		fmt.Printf("- busy functions:\n")
		printGroupBits(d[18:30])
	}
	fmt.Printf("\n")
	return
}
